package org.idtem.component.AnalisisSintacticoAnnotation;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

import org.apache.uima.analysis_component.CasAnnotator_ImplBase;
import org.apache.uima.analysis_engine.AnalysisEngineProcessException;
import org.apache.uima.cas.CAS;
import org.apache.uima.cas.FSIterator;
import org.apache.uima.cas.FSTypeConstraint;
import org.apache.uima.jcas.JCas;
import org.apache.uima.jcas.cas.FSArray;
import org.idtem.component.analisissintactico.BaseSyntacticFunction;
import org.idtem.component.analisissintactico.SyntacticLeafNode;
import org.idtem.component.analisissintactico.SyntacticNode;
import org.idtem.component.analisissintactico.SyntacticSentence;
import org.idtem.component.freeling.Adjetivo;
import org.idtem.component.freeling.Adverbio;
import org.idtem.component.freeling.Freeling2;
import org.idtem.component.freeling.Nombre;
import org.idtem.component.freeling.Sentencia;
import org.idtem.component.freeling.Verbo;
import org.idtem.utils.freeling.AnalisisSintacticoNodoBaseFreeling;
import org.idtem.utils.freeling.AnalisisSintacticoNodoHojaFreeling;
import org.idtem.utils.freeling.AnalisisSintaticoNodoFreeling;
import org.idtem.utils.freeling.RunComandFreeling;
import org.idtem.utils.logger.LoggerHelper;


public class AnalisisSintacticoAnnotation extends CasAnnotator_ImplBase {

		
	@Override
	public void process(CAS aJCas) throws AnalysisEngineProcessException {
		JCas javaCas = null;
		try {
			javaCas = aJCas.getJCas();
			LoggerHelper.getInstance().getAnalisisSintacticoLogguer().info("++++ Inicio Analisis Sintactico Component");
					
			String docText = aJCas.getDocumentText();
		    
		    ArrayList<AnalisisSintacticoNodoBaseFreeling> sintaticText = RunComandFreeling.analisisSintactico(docText);
		   
		    Collection<Sentencia> collectionSentencia = obtenerSentenciasFreeling(javaCas);
		    if (collectionSentencia.size() !=  sintaticText.size())
		    	throw new Exception();
		    ArrayList<Freeling2> tokensFreeling = new ArrayList<Freeling2>(obtenerTokensFreeling(javaCas));
			int[] index = new int[1];
			index[0] = 0;
			Iterator<AnalisisSintacticoNodoBaseFreeling> itResultadoFreeling = sintaticText.iterator();
			for (Sentencia sentenciaAnnotation : obtenerSentenciasFreeling(javaCas)) 
		    {
				AnalisisSintacticoNodoBaseFreeling resultadoSintacticoFreelingSentencia = itResultadoFreeling.next();
				BaseSyntacticFunction baseSntacticFunction = SetInfoSintacticaOracion(resultadoSintacticoFreelingSentencia, sentenciaAnnotation, tokensFreeling, index, javaCas);
				SyntacticSentence syntacticSentence = new SyntacticSentence(javaCas);
				syntacticSentence.setBaseSyntacticFunctionReference(baseSntacticFunction);
				syntacticSentence.setSentenceReference(sentenciaAnnotation);
				syntacticSentence.setBegin(sentenciaAnnotation.getBegin());
				syntacticSentence.setEnd(sentenciaAnnotation.getEnd());
				syntacticSentence.addToIndexes();
		    }
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		LoggerHelper.getInstance().getAnalisisSintacticoLogguer().info("---- Fin Analisis Sintactico Component");
	}
	
	private BaseSyntacticFunction SetInfoSintacticaOracion(AnalisisSintacticoNodoBaseFreeling resSintacticoFreelingSentencia, Sentencia sentenciaAnnotation, ArrayList<Freeling2> freeling2SentenceCollection, int[] index, JCas jcas) throws Exception {
		if (resSintacticoFreelingSentencia instanceof AnalisisSintaticoNodoFreeling)
		{
			AnalisisSintaticoNodoFreeling nodo = (AnalisisSintaticoNodoFreeling)resSintacticoFreelingSentencia;
			ArrayList<BaseSyntacticFunction> childsAnnotation = new ArrayList<BaseSyntacticFunction>();
			for (AnalisisSintacticoNodoBaseFreeling hijo : nodo.getHijos()) {
				BaseSyntacticFunction childNode = SetInfoSintacticaOracion(hijo, sentenciaAnnotation, freeling2SentenceCollection, index, jcas);
				childsAnnotation.add(childNode);
			}
			SyntacticNode returnNode = new SyntacticNode(jcas);
			returnNode.setBegin(childsAnnotation.get(0).getBegin());
			returnNode.setEnd(childsAnnotation.get(childsAnnotation.size() -1).getEnd());
			FSArray chilsArray = new FSArray(jcas, childsAnnotation.size());
			for (int i = 0; i < childsAnnotation.size(); i++)
			{
				chilsArray.set(i,childsAnnotation.get(i));
			}
			returnNode.setChildFunctions(chilsArray);
			returnNode.setFunction(nodo.getFuncionSintactica());
			returnNode.addToIndexes();
			return returnNode;
		}
		else if (resSintacticoFreelingSentencia instanceof AnalisisSintacticoNodoHojaFreeling)
		{
			AnalisisSintacticoNodoHojaFreeling hoja = (AnalisisSintacticoNodoHojaFreeling)resSintacticoFreelingSentencia;
			SyntacticLeafNode returnleafNode = new SyntacticLeafNode(jcas);
			Freeling2 freeling2 = freeling2SentenceCollection.get(index[0]);
			index[0]++;
			returnleafNode.setBegin(freeling2.getBegin());
			returnleafNode.setEnd(freeling2.getEnd());
			returnleafNode.setFreelingReference(freeling2);
			returnleafNode.addToIndexes();
			return returnleafNode;
		}
		throw new Exception();
			
	}
	
	private Collection<Freeling2> obtenerTokensFreeling(JCas aJCas) 
	{
		Collection<Freeling2> tokens = new ArrayList<Freeling2>();
		
		FSIterator it = aJCas.getAnnotationIndex().iterator();
		FSTypeConstraint constraint = aJCas.getConstraintFactory().createTypeConstraint();
		constraint.add((new Freeling2(aJCas)).getType());
		it = aJCas.createFilteredIterator(it, constraint);
		while (it.hasNext()) 
		{
			Freeling2 fa = (Freeling2)it.next();
			tokens.add(fa);
		}
		return tokens;
	}

	private Collection<Sentencia> obtenerSentenciasFreeling(JCas aJCas) 
	{
		Collection<Sentencia> sentences = new ArrayList<Sentencia>();
		
		FSIterator it = aJCas.getAnnotationIndex().iterator();
		FSTypeConstraint constraint = aJCas.getConstraintFactory().createTypeConstraint();
		constraint.add((new Sentencia(aJCas)).getType());
		it = aJCas.createFilteredIterator(it, constraint);
		while (it.hasNext()) 
		{
			Sentencia fa = (Sentencia)it.next();
			sentences.add(fa);
		}
		return sentences;
	}
	
		


	

}
